home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_ATxgopher.idb / usr / freeware / src / xgopher.1.3 / KeyWSink.c.z / KeyWSink.c
C/C++ Source or Header  |  1998-01-21  |  15KB  |  541 lines

  1.  
  2. /***********************************************************
  3. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  4. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  5.  
  6.                         All Rights Reserved
  7.  
  8. Permission to use, copy, modify, and distribute this software and its 
  9. documentation for any purpose and without fee is hereby granted, 
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in 
  12. supporting documentation, and that the names of Digital or MIT not be
  13. used in advertising or publicity pertaining to distribution of the
  14. software without specific, written prior permission.  
  15.  
  16. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  17. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  18. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  19. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  20. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  21. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  22. SOFTWARE.
  23.  
  24. ******************************************************************/
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28.  
  29. #include <X11/Xlib.h>
  30. #include <X11/Xutil.h>
  31. #include <X11/Xatom.h>
  32. #include <X11/IntrinsicP.h>
  33. #include <X11/StringDefs.h>
  34. #include <X11/Xaw/XawInit.h>
  35. #include "KeyWSinkP.h"
  36. #include <X11/Xaw/AsciiSinkP.h>
  37. #include <X11/Xaw/AsciiSrcP.h>    /* For source function defs. */
  38. #include <X11/Xaw/TextP.h>    /* I also reach into the text widget. */
  39.  
  40. #ifdef GETLASTPOS
  41. #undef GETLASTPOS        /* We will use our own GETLASTPOS. */
  42. #endif
  43.  
  44. #define GETLASTPOS XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, TRUE)
  45.  
  46. static void Initialize(), Destroy();
  47. static Boolean SetValues();
  48.  
  49. static void DisplayText();
  50.  
  51.  
  52. #define offset(field) XtOffsetOf(KeyWSinkRec, keyw_sink.field)
  53.  
  54. static XtResource resources[] = {
  55.     {XtNwordList, XtCWordList, XtRPointer, sizeof(char **),
  56.     offset(wordList), XtRImmediate, (XtPointer) NULL}
  57. };
  58. #undef offset
  59.  
  60. #define SuperClass        (&asciiSinkClassRec)
  61. KeyWSinkClassRec keyWSinkClassRec = {
  62.   {
  63. /* core_class fields */    
  64.     /* superclass          */    (WidgetClass) SuperClass,
  65.     /* class_name          */    "KeyWSink",
  66.     /* widget_size          */    sizeof(KeyWSinkRec),
  67.     /* class_initialize       */    XawInitializeWidgetSet,
  68.     /* class_part_initialize    */    NULL,
  69.     /* class_inited           */    FALSE,
  70.     /* initialize          */    Initialize,
  71.     /* initialize_hook        */    NULL,
  72.     /* obj1              */    NULL,
  73.     /* obj2              */    NULL,
  74.     /* obj3              */    0,
  75.     /* resources          */    resources,
  76.     /* num_resources          */    XtNumber(resources),
  77.     /* xrm_class          */    NULLQUARK,
  78.     /* obj4              */    FALSE,
  79.     /* obj5              */    FALSE,
  80.     /* obj6            */    FALSE,
  81.     /* obj7              */    FALSE,
  82.     /* destroy              */    Destroy,
  83.     /* obj8              */    NULL,
  84.     /* obj9              */    NULL,
  85.     /* set_values          */    SetValues,
  86.     /* set_values_hook        */    NULL,
  87.     /* obj10            */    NULL,
  88.     /* get_values_hook        */    NULL,
  89.     /* obj11             */    NULL,
  90.     /* version            */    XtVersion,
  91.     /* callback_private       */    NULL,
  92.     /* obj12               */    NULL,
  93.     /* obj13            */    NULL,
  94.     /* obj14            */    NULL,
  95.     /* extension        */    NULL
  96.   },
  97. /* text_sink_class fields */
  98.   {
  99.     /* DisplayText              */      DisplayText,
  100.     /* InsertCursor             */      XtInheritInsertCursor,
  101.     /* ClearToBackground        */      XtInheritClearToBackground,
  102.     /* FindPosition             */      XtInheritFindPosition,
  103.     /* FindDistance             */      XtInheritFindDistance,
  104.     /* Resolve                  */      XtInheritResolve,
  105.     /* MaxLines                 */      XtInheritMaxLines,
  106.     /* MaxHeight                */      XtInheritMaxHeight,
  107.     /* SetTabs                  */      XtInheritSetTabs,
  108.     /* GetCursorBounds          */      XtInheritGetCursorBounds
  109.   },
  110. /* ascii_sink_class fields */
  111.   {
  112.     /* unused            */    0
  113.   },
  114. /* keyw_sink_class fields */
  115.   {
  116.     /* unused            */    0
  117.   }
  118. };
  119.  
  120. WidgetClass keyWSinkObjectClass = (WidgetClass)&keyWSinkClassRec;
  121.  
  122. /* Utilities */
  123.  
  124.  
  125. /* matchw
  126.    given a string buffer and a null-terminated list of words, find
  127.    the leftmost position in the buffer that matches one of the words
  128.    in the list, if any.  Returns the offset in the buffer of first match,
  129.    -1 if no match.  Also, the int* parameter matchLen is set to the
  130.    length of the match. */
  131.  
  132. static int
  133. matchw(buf, len, words, matchLen)
  134. char    *buf;
  135. int    len;
  136. char    *words[];
  137. int    *matchLen;
  138. {
  139.     int    i, j, k;
  140.     int    left = len;
  141.     int    wLen, last;
  142.     char    *start=buf, *bp, *wp;
  143.     int    match, tested;
  144.  
  145.     /* loop through the characters in the buffer */
  146.  
  147.     *matchLen = 0;
  148.     if (words == NULL) return -1;
  149.  
  150.     while (left > 0) {
  151.  
  152.         /* loop through each word in the word list */
  153.  
  154.         tested = False;
  155.         for (k=0; words[k]!=NULL; k++) {
  156.  
  157.             /* if too few characters left in buffer, next word */
  158.  
  159.             wLen = strlen(words[k]);
  160.             if ((last = left - wLen + 1) <= 0) continue;
  161.             tested = True;
  162.  
  163.             /* loop through each character in the word */
  164.  
  165.             match = True;
  166.             bp=buf; wp=words[k]; 
  167.             for (i=0; i < wLen; i++) {
  168.                 if ((wp[i] != bp[i]) && (toupper(wp[i]) != bp[i])) {
  169.                     match = False;
  170.                     break;
  171.                 }
  172.             }
  173.  
  174.             if (match) {
  175.                 *matchLen = wLen;
  176.                 return (buf - start);
  177.             }
  178.         }
  179.  
  180.         if (! tested) return -1;
  181.  
  182.         left--;
  183.         buf++;
  184.     }
  185.  
  186.     return -1;
  187. }
  188.  
  189.  
  190. static int 
  191. CharWidth (w, x, c)
  192. Widget w;
  193. int x;
  194. unsigned char c;
  195. {
  196.     register int    i, width, nonPrinting;
  197.     KeyWSinkObject sink = (KeyWSinkObject) w;
  198.     XFontStruct *font = sink->text_sink.font;
  199.     Position *tab;
  200.  
  201.     if ( c == XawLF ) return(0);
  202.  
  203.     if (c == XawTAB) {
  204.     /* Adjust for Left Margin. */
  205.     x -= ((TextWidget) XtParent(w))->text.margin.left;
  206.  
  207.     if (x >= (int)XtParent(w)->core.width) return 0;
  208.     for (i = 0, tab = sink->text_sink.tabs ; 
  209.          i < sink->text_sink.tab_count ; i++, tab++) {
  210.         if (x < *tab) {
  211.         if (*tab < (int)XtParent(w)->core.width)
  212.             return *tab - x;
  213.         else
  214.             return 0;
  215.         }
  216.     }
  217.     return 0;
  218.     }
  219.  
  220.     if ( (nonPrinting = (c < (unsigned char) XawSP)) )
  221.     if (sink->ascii_sink.display_nonprinting)
  222.         c += '@';
  223.     else {
  224.         c = XawSP;
  225.         nonPrinting = False;
  226.     }
  227.  
  228.     if (font->per_char &&
  229.         (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
  230.     width = font->per_char[c - font->min_char_or_byte2].width;
  231.     else
  232.     width = font->min_bounds.width;
  233.  
  234.     if (nonPrinting)
  235.     width += CharWidth(w, x, (unsigned char) '^');
  236.  
  237.     return width;
  238. }
  239.  
  240. /*    Function Name: PaintText
  241.  *    Description: Actually paints the text into the windoe.
  242.  *    Arguments: w - the text widget.
  243.  *                 gc - gc to paint text with.
  244.  *                 x, y - location to paint the text.
  245.  *                 buf, len - buffer and length of text to paint.
  246.  *    Returns: the width of the text painted, or 0.
  247.  *
  248.  * NOTE:  If this string attempts to paint past the end of the window
  249.  *        then this function will return zero.
  250.  */
  251.  
  252. static Dimension
  253. PaintText(w, gc, x, y, buf, len)
  254. Widget w;
  255. GC gc;
  256. Position x, y;
  257. unsigned char * buf;
  258. int len;
  259. {
  260.     KeyWSinkObject sink = (KeyWSinkObject) w;
  261.     TextWidget ctx = (TextWidget) XtParent(w);
  262.  
  263.     Position max_x;
  264.     Dimension width = XTextWidth(sink->text_sink.font, (char *) buf, len); 
  265.     max_x = (Position) ctx->core.width;
  266.  
  267.     if ( ((int) width) <= -x)               /* Don't draw if we can't see it. */
  268.       return(width);
  269.  
  270.     XDrawImageString(XtDisplay(ctx), XtWindow(ctx), gc, 
  271.              (int) x, (int) y, (char *) buf, len);
  272.     if ( (((Position) width + x) > max_x) && (ctx->text.margin.right != 0) ) {
  273.     x = ctx->core.width - ctx->text.margin.right;
  274.     width = ctx->text.margin.right;
  275.     XFillRectangle(XtDisplay((Widget) ctx), XtWindow( (Widget) ctx),
  276.                sink->ascii_sink.normgc, (int) x,
  277.                (int) y - sink->text_sink.font->ascent, 
  278.                (unsigned int) width,
  279.                (unsigned int) (sink->text_sink.font->ascent +
  280.                        sink->text_sink.font->descent));
  281.     return(0);
  282.     }
  283.     return(width);
  284. }
  285.  
  286. /*    Function Name: PaintKeyW
  287.  *    Description: highlight selected list of keywords, then calls function
  288.  *                   to actually paint the text into the window.
  289.  *    Arguments: w - the text widget.
  290.  *                 gc - gc to paint text with.
  291.  *                 invgc - gc to highlight text with.
  292.  *                 x, y - location to paint the text.
  293.  *                 buf, len - buffer and length of text to paint.
  294.  *    Returns: the width of the text painted, or 0.
  295.  *
  296.  * NOTE:  If this string attempts to paint past the end of the window
  297.  *        then this function will return zero.
  298.  */
  299.  
  300. static Dimension
  301. PaintKeyW(w, gc, invgc, x, y, buf, len)
  302. Widget w;
  303. GC gc, invgc;
  304. Position x, y;
  305. unsigned char * buf;
  306. int len;
  307. {
  308.     KeyWSinkObject sink = (KeyWSinkObject) w;
  309.     TextWidget ctx = (TextWidget) XtParent(w);
  310.     int    first, nch;
  311.     Dimension px, xlen=0;
  312.  
  313.     first = matchw(buf, len, sink->keyw_sink.wordList, &nch);
  314.     while (first != -1) {
  315.     if (first != 0) {
  316.         if ((px = PaintText(w, gc, x+xlen, y, buf, first)) == 0)
  317.                                 return 0;
  318.             xlen += px;
  319.             len -= first;
  320.             buf += first;
  321.     }
  322.         if ((px = PaintText(w, invgc, x+xlen, y, buf, nch)) == 0) return 0;
  323.         xlen += px;
  324.         len -= nch;
  325.         buf += nch;
  326.  
  327.         first = matchw(buf, len, sink->keyw_sink.wordList, &nch);
  328.     }
  329.  
  330.     if (len > 0) {
  331.     if ((px = PaintText(w, gc, x+xlen, y, buf, len)) == 0) return 0;
  332.         xlen += px;
  333.     }
  334.  
  335.     return xlen;
  336. }
  337.  
  338. /* Sink Object Functions */
  339.  
  340. /*
  341.  * This function does not know about drawing more than one line of text.
  342.  */
  343.  
  344. static void 
  345. DisplayText(w, x, y, pos1, pos2, highlight)
  346. Widget w;
  347. Position x, y;
  348. Boolean highlight;
  349. XawTextPosition pos1, pos2;
  350. {
  351.     KeyWSinkObject sink = (KeyWSinkObject) w;
  352.     Widget source = XawTextGetSource(XtParent(w));
  353.     unsigned char buf[BUFSIZ];
  354.  
  355.     int j, k;
  356.     XawTextBlock blk;
  357.     GC gc = highlight ? sink->ascii_sink.invgc : sink->ascii_sink.normgc;
  358.     GC invgc = highlight ? sink->ascii_sink.normgc : sink->ascii_sink.invgc;
  359.  
  360.     if (!sink->ascii_sink.echo) return;
  361.  
  362.     y += sink->text_sink.font->ascent;
  363.     for ( j = 0 ; pos1 < pos2 ; ) {
  364.     pos1 = XawTextSourceRead(source, pos1, &blk, pos2 - pos1);
  365.     for (k = 0; k < blk.length; k++) {
  366.         if (j >= BUFSIZ) {    /* buffer full, dump the text. */
  367.         if (sink->keyw_sink.wordList == NULL)
  368.                 x += PaintText(w, gc, x, y, buf, j);
  369.         else
  370.                 x += PaintKeyW(w, gc, invgc, x, y, buf, j);
  371.         j = 0;
  372.         }
  373.         buf[j] = blk.ptr[k];
  374.         if (buf[j] == XawLF)    /* line feeds ('\n') are not printed. */
  375.             continue;
  376.  
  377.         else if (buf[j] == '\t') {
  378.             Position temp = 0;
  379.         Dimension width;
  380.  
  381.         /*
  382.             if ((j != 0) && ((temp = PaintText(w, gc, x, y, buf, j)) == 0))
  383.           return;
  384.         */
  385.             if (j != 0) {
  386.             if (sink->keyw_sink.wordList == NULL)
  387.             temp = PaintText(w, gc, x, y, buf, j);
  388.             else
  389.             temp = PaintKeyW(w, gc, invgc, x, y, buf, j);
  390.             if (temp == 0) return;
  391.         }
  392.  
  393.             x += temp;
  394.         width = CharWidth(w, x, (unsigned char) '\t');
  395.         XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),
  396.                    invgc, (int) x,
  397.                    (int) y - sink->text_sink.font->ascent,
  398.                    (unsigned int) width,
  399.                    (unsigned int) (sink->text_sink.font->ascent +
  400.                            sink->text_sink.font->descent));
  401.         x += width;
  402.         j = -1;
  403.         }
  404.         else if ( buf[j] < (unsigned char) ' ' ) {
  405.             if (sink->ascii_sink.display_nonprinting) {
  406.             buf[j + 1] = buf[j] + '@';
  407.             buf[j] = '^';
  408.             j++;
  409.         }
  410.         else
  411.             buf[j] = ' ';
  412.         }
  413.         j++;
  414.     }
  415.     }
  416.     if (j > 0)
  417.     if (sink->keyw_sink.wordList == NULL)
  418.             (void) PaintText(w, gc, x, y, buf, j);
  419.     else
  420.             (void) PaintKeyW(w, gc, invgc, x, y, buf, j);
  421. }
  422.  
  423. #define insertCursor_width 6
  424. #define insertCursor_height 3
  425. static char insertCursor_bits[] = {0x0c, 0x1e, 0x33};
  426.  
  427. static Pixmap
  428. CreateInsertCursor(s)
  429. Screen *s;
  430. {
  431.     return (XCreateBitmapFromData (DisplayOfScreen(s), RootWindowOfScreen(s),
  432.           insertCursor_bits, insertCursor_width, insertCursor_height));
  433. }
  434.  
  435.  
  436. static void
  437. GetGC(sink)
  438. KeyWSinkObject sink;
  439. {
  440.     XtGCMask valuemask = (GCFont | 
  441.               GCGraphicsExposures | GCForeground | GCBackground );
  442.     XGCValues values;
  443.  
  444.     values.font = sink->text_sink.font->fid;
  445.     values.graphics_exposures = (Bool) FALSE;
  446.     
  447.     values.foreground = sink->text_sink.foreground;
  448.     values.background = sink->text_sink.background;
  449.     sink->ascii_sink.normgc = XtGetGC((Widget)sink, valuemask, &values);
  450.     
  451.     values.foreground = sink->text_sink.background;
  452.     values.background = sink->text_sink.foreground;
  453.     sink->ascii_sink.invgc = XtGetGC((Widget)sink, valuemask, &values);
  454.     
  455.     values.function = GXxor;
  456.     values.background = (unsigned long) 0L;    /* (pix ^ 0) = pix */
  457.     values.foreground = (sink->text_sink.background ^ 
  458.              sink->text_sink.foreground);
  459.     valuemask = GCGraphicsExposures | GCFunction | GCForeground | GCBackground;
  460.     
  461.     sink->ascii_sink.xorgc = XtGetGC((Widget)sink, valuemask, &values);
  462. }
  463.  
  464.  
  465. /***** Public routines *****/
  466.  
  467. /*    Function Name: Initialize
  468.  *    Description: Initializes the TextSink Object.
  469.  *    Arguments: request, new - the requested and new values for the object
  470.  *                                instance.
  471.  *    Returns: none.
  472.  *
  473.  */
  474.  
  475. /* ARGSUSED */
  476. static void
  477. Initialize(request, new)
  478. Widget request, new;
  479. {
  480.     KeyWSinkObject sink = (KeyWSinkObject) new;
  481.  
  482.     GetGC(sink);
  483.     
  484.     sink->ascii_sink.insertCursorOn= CreateInsertCursor(XtScreenOfObject(new));
  485.     sink->ascii_sink.laststate = XawisOff;
  486.     sink->ascii_sink.cursor_x = sink->ascii_sink.cursor_y = 0;
  487. }
  488.  
  489. /*    Function Name: Destroy
  490.  *    Description: This function cleans up when the object is 
  491.  *                   destroyed.
  492.  *    Arguments: w - the KeyWSink Object.
  493.  *    Returns: none.
  494.  */
  495.  
  496. static void
  497. Destroy(w)
  498. Widget w;
  499. {
  500.    KeyWSinkObject sink = (KeyWSinkObject) w;
  501.  
  502.    XtReleaseGC(w, sink->ascii_sink.normgc);
  503.    XtReleaseGC(w, sink->ascii_sink.invgc);
  504.    XtReleaseGC(w, sink->ascii_sink.xorgc);
  505.    XFreePixmap(XtDisplayOfObject(w), sink->ascii_sink.insertCursorOn);
  506. }
  507.  
  508. /*    Function Name: SetValues
  509.  *    Description: Sets the values for the KeyWSink
  510.  *    Arguments: current - current state of the object.
  511.  *                 request - what was requested.
  512.  *                 new - what the object will become.
  513.  *    Returns: True if redisplay is needed.
  514.  */
  515.  
  516. /* ARGSUSED */
  517. static Boolean
  518. SetValues(current, request, new)
  519. Widget current, request, new;
  520. {
  521.     KeyWSinkObject w = (KeyWSinkObject) new;
  522.     KeyWSinkObject old_w = (KeyWSinkObject) current;
  523.  
  524.     if (w->text_sink.font != old_w->text_sink.font
  525.     || w->text_sink.background != old_w->text_sink.background
  526.     || w->text_sink.foreground != old_w->text_sink.foreground) {
  527.     XtReleaseGC((Widget)w, w->ascii_sink.normgc);
  528.     XtReleaseGC((Widget)w, w->ascii_sink.invgc);
  529.     XtReleaseGC((Widget)w, w->ascii_sink.xorgc);
  530.     GetGC(w);
  531.     ((TextWidget)XtParent(new))->text.redisplay_needed = True;
  532.     } else {
  533.     if ( (w->ascii_sink.echo != old_w->ascii_sink.echo) ||
  534.          (w->ascii_sink.display_nonprinting != 
  535.                                      old_w->ascii_sink.display_nonprinting) )
  536.         ((TextWidget)XtParent(new))->text.redisplay_needed = True;
  537.     }
  538.     
  539.     return False;
  540. }
  541.